package com.jdj.framework.dao.mybatis.dao.impl;

import com.jdj.framework.core.base.utils.MapUtils;
import com.jdj.framework.core.base.utils.StringUtils;
import com.jdj.framework.core.base.vo.PageInfo;
import com.jdj.framework.dao.mybatis.dao.MyBatisDao;
import com.jdj.framework.dao.mybatis.entity.BaseEntity;
import com.jdj.framework.dao.mybatis.entity.condition.BaseEntityCondition;
import com.jdj.framework.dao.mybatis.mapper.BaseMapper;
import com.jdj.framework.dao.mybatis.mapper.utils.MapperUtils;
import com.jdj.framework.dao.mybatis.utils.EntityUtil;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.regex.Pattern;
import javax.persistence.OptimisticLockException;
import org.mybatis.spring.support.SqlSessionDaoSupport;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * MyBatisDao 实现类
 *
 * @author caijinbang
 * @date 2019-04-14 11:45
 */
public class MyBatisDaoImpl extends SqlSessionDaoSupport implements MyBatisDao {

    private final Logger logger = LoggerFactory.getLogger(MyBatisDaoImpl.class);

    private static final String DYNAMIC_INSERT_SQL_STATEMENT_ID = "com.jdj.framework.FrameworkMapper.DynamicInsertSql";

    private static final String DYNAMIC_DELETE_SQL_STATEMENT_ID = "com.jdj.framework.FrameworkMapper.DynamicDeleteSql";

    private static final String DYNAMIC_UPDATE_SQL_STATEMENT_ID = "com.jdj.framework.FrameworkMapper.DynamicUpdateSql";

    private static final String DYNAMIC_SELECT_SQL_STATEMENT_ID = "com.jdj.framework.FrameworkMapper.DynamicSelectSql";

    private static final String DYNAMIC_SQL = "dynamicSql";

    private static final Pattern insertPattern = Pattern.compile("^[insert/s].*");

    private static final Pattern deletePattern = Pattern.compile("^[delete/s].*");

    private static final Pattern updatePattern = Pattern.compile("^[update/s].*");

    @Override
    public <Condition extends BaseEntityCondition> int countByCondition(Condition condition) {
        BaseMapper entityMapper = MapperUtils
            .getMapperInstanceByEntityClass(condition.getEntityClass());
        return entityMapper.countByCondition(condition);
    }

    @Override
    public <Entity extends BaseEntity, Condition extends BaseEntityCondition> List<Entity> selectByCondition(
        Condition condition) {
        BaseMapper entityMapper = MapperUtils
            .getMapperInstanceByEntityClass(condition.getEntityClass());
        return entityMapper.selectByCondition(condition);
    }

    @Override
    public <Entity extends BaseEntity, Condition extends BaseEntityCondition> List<Entity> selectByConditionWithBLOBs(
        Condition condition) {
        BaseMapper entityMapper = MapperUtils
            .getMapperInstanceByEntityClass(condition.getEntityClass());
        return entityMapper.selectByConditionWithBLOBs(condition);
    }

    @Override
    public <Entity extends BaseEntity, Condition extends BaseEntityCondition> Entity selectOneByCondition(
        Condition condition) {
        List<Entity> entities = this.selectByCondition(condition);
        if (entities == null || entities.size() <= 0) {
            return null;
        } else {
            return entities.get(0);
        }
    }

    @Override
    public <Entity extends BaseEntity, Condition extends BaseEntityCondition> Entity selectOneByConditionWithBLOBs(
        Condition condition) {
        List<Entity> entities = this.selectByConditionWithBLOBs(condition);
        if (entities == null || entities.size() <= 0) {
            return null;
        } else {
            return entities.get(0);
        }
    }

    @Override
    public <Condition extends BaseEntityCondition> PageInfo selectPageByCondition(
        Condition condition) {
        PageInfo page = condition.getPage();
        page.setTotalRecord(this.countByCondition(condition));
        page.setRecords(this.selectByCondition(condition));
        return page;
    }

    @Override
    public <Entity extends BaseEntity> int insert(Entity entity) {
        Serializable primaryKeyValue = insertOne(entity);
        if (primaryKeyValue != null) {
            return 1;
        } else {
            return 0;
        }
    }

    @Override
    public <Entity extends BaseEntity> int insert(List<Entity> entities) {
        List<Serializable> primaryKeys = this.insertBatch(entities);
        if (primaryKeys != null) {
            return primaryKeys.size();
        } else {
            return 0;
        }
    }

    @Override
    public <Entity extends BaseEntity> int insertList(List<Entity> entities) {
        return this.insertListBatch(entities);
    }

    @Override
    public <Entity extends BaseEntity> List<Serializable> insertListWithPrimaryKeys(
        List<Entity> entities) {
        //所有主键
        List<Serializable> primaryKeys = new ArrayList<>();
        if (insertListBatch(entities) > 0) {
            for (Entity entity : entities) {
                primaryKeys.add(getPrimaryKeyValue(entity));
            }
        }
        return primaryKeys;
    }

    @Override
    @SuppressWarnings("unchecked")
    public <Entity extends BaseEntity, T> T insertWithPrimaryKey(Entity entity) {
        return (T) insertOne(entity);
    }

    @Override
    public <Entity extends BaseEntity> List<Serializable> insertWithPrimaryKeys(
        List<Entity> entities) {
        return this.insertBatch(entities);
    }

    @Override
    public <Entity extends BaseEntity> Entity insertWithQuery(Entity entity) {
        Serializable primaryKeyValue = insertOne(entity);
        if (primaryKeyValue != null) {
            return this.selectByPrimaryKey(entity);
        } else {
            return null;
        }
    }

    @SuppressWarnings("unchecked")
    @Override
    public <Entity extends BaseEntity> List<Entity> insertWithQuery(List<Entity> entities) {
        //
        List<Entity> queryEntities = new ArrayList();
        //1、所有主键
        List<Serializable> primaryKeys = insertBatch(entities);
        if (primaryKeys != null && primaryKeys.size() > 0) {
            //2、实体Class
            Class<Entity> entityClass = (Class<Entity>) entities.get(0).getClass();
            //3、执行批量查询，（TODO:可优化批量查询，采用 in 方式）
            for (Serializable primaryKeyValue : primaryKeys) {
                Entity entity = selectByPrimaryKey(entityClass, primaryKeyValue);
                queryEntities.add(entity);
            }
        }
        return queryEntities;
    }

    @Override
    public <Entity extends BaseEntity> int deleteByPrimaryKey(Class<Entity> entityClass,
        Serializable primaryKeyValue) {
        BaseMapper entityMapper = MapperUtils.getMapperInstanceByEntityClass(entityClass);
        return entityMapper.deleteByPrimaryKey(entityClass, primaryKeyValue);
    }

    @Override
    public <Entity extends BaseEntity> int delete(Entity entity) {
        return this.deleteByPrimaryKey(entity.getClass(), getPrimaryKeyValue(entity));
    }

    @Override
    public <Entity extends BaseEntity, Condition extends BaseEntityCondition> int updateByCondition(
        Entity entity,
        Condition condition) {
        BaseMapper entityMapper = MapperUtils
            .getMapperInstanceByEntityClass(condition.getEntityClass());
        return entityMapper.updateByCondition(entity, condition);
    }

    @Override
    @SuppressWarnings("unchecked")
    public <Entity extends BaseEntity> int delete(List<Entity> entities) {
        if (entities == null || entities.isEmpty()) {
            return 0;
        }
        //1、实体Class
        Class<Entity> entityClass = (Class<Entity>) entities.get(0).getClass();
        //2、表名
        String tableName = EntityUtil.getTableName(entityClass);
        //3、主键列名
        String primaryKeyColumn = EntityUtil.getPrimaryKeyColumnName(entityClass);
        //4、批量删除sql（TODO:改为 in 条件）
        StringBuffer sql = new StringBuffer("delete from ");
        sql.append(tableName);
        sql.append(" where ");
        sql.append(primaryKeyColumn);
        sql.append(" = #{id}");
        //5、批量参数
        List<Map<String, Object>> parameters = new ArrayList();
        for (Entity entity : entities) {
            Map<String, Object> parameter = new HashMap();
            parameter.put("id", this.getPrimaryKeyValue(entity));
            parameters.add(parameter);
        }
        //6、执行删除
        return this.deleteByDynamicSql(sql.toString(), parameters);
    }

    @Override
    public <Entity extends BaseEntity> int update(Entity entity) {
        Serializable primaryKeyValue = updateOne(entity);
        if (primaryKeyValue != null) {
            return 1;
        } else {
            return 0;
        }
    }

    @Override
    public <Entity extends BaseEntity> int updateNotEmpty(Entity entity) {
        Serializable primaryKeyValue = updateNotEmptyOne(entity);
        if (primaryKeyValue != null) {
            return 1;
        } else {
            return 0;
        }
    }

    @Override
    public <Entity extends BaseEntity> int updateNotNull(Entity entity) {
        Serializable primaryKeyValue = updateNotNullOne(entity);
        if (primaryKeyValue != null) {
            return 1;
        } else {
            return 0;
        }
    }

    @Override
    public <Condition extends BaseEntityCondition> int deleteByCondition(Condition condition) {
        BaseMapper entityMapper = MapperUtils
            .getMapperInstanceByEntityClass(condition.getEntityClass());
        return entityMapper.deleteByCondition(condition);
    }

    @Override
    public <Entity extends BaseEntity> int update(List<Entity> entities) {
        List<Serializable> primaryKeys = this.updateBatch(entities);
        if (primaryKeys != null) {
            return primaryKeys.size();
        } else {
            return 0;
        }
    }

    @Override
    public <Entity extends BaseEntity> int updateNotEmpty(List<Entity> entities) {
        List<Serializable> primaryKeys = this.updateNotEmptyBatch(entities);
        if (primaryKeys != null) {
            return primaryKeys.size();
        } else {
            return 0;
        }
    }

    @Override
    public <Entity extends BaseEntity> int updateNotNull(List<Entity> entities) {
        List<Serializable> primaryKeys = this.updateNotNullBatch(entities);
        if (primaryKeys != null) {
            return primaryKeys.size();
        } else {
            return 0;
        }
    }

    @Override
    @SuppressWarnings("unchecked")
    public <Entity extends BaseEntity, T> T updateWithPrimaryKey(Entity entity) {
        return (T) updateOne(entity);
    }

    @Override
    @SuppressWarnings("unchecked")
    public <Entity extends BaseEntity, T> T updateNotEmptyWithPrimaryKey(Entity entity) {
        return (T) updateNotEmptyOne(entity);
    }

    @Override
    @SuppressWarnings("unchecked")
    public <Entity extends BaseEntity, T> T updateNotNullWithPrimaryKey(Entity entity) {
        return (T) updateNotNullOne(entity);
    }

    @Override
    public <Entity extends BaseEntity> List<Serializable> updateWithPrimaryKeys(
        List<Entity> entities) {
        return this.updateBatch(entities);
    }

    @Override
    public <Entity extends BaseEntity> List<Serializable> updateNotEmptyWithPrimaryKeys(
        List<Entity> entities) {
        return this.updateNotEmptyBatch(entities);
    }

    @Override
    public <Entity extends BaseEntity> List<Serializable> updateNotNullWithPrimaryKeys(
        List<Entity> entities) {
        return this.updateNotNullBatch(entities);
    }

    @Override
    public <Entity extends BaseEntity> Entity updateWithQuery(Entity entity) {
        Serializable primaryKeyValue = updateOne(entity);
        if (primaryKeyValue != null) {
            return this.selectByPrimaryKey(entity);
        } else {
            return null;
        }
    }

    @Override
    public <Entity extends BaseEntity> Entity updateNotEmptyWithQuery(Entity entity) {
        Serializable primaryKeyValue = updateNotEmptyOne(entity);
        if (primaryKeyValue != null) {
            return this.selectByPrimaryKey(entity);
        } else {
            return null;
        }
    }

    @Override
    public <Entity extends BaseEntity> Entity updateNotNullWithQuery(Entity entity) {
        Serializable primaryKeyValue = updateNotNullOne(entity);
        if (primaryKeyValue != null) {
            return this.selectByPrimaryKey(entity);
        } else {
            return null;
        }
    }

    @Override
    @SuppressWarnings("unchecked")
    public <Entity extends BaseEntity> List<Entity> updateWithQuery(List<Entity> entities) {
        //
        List<Entity> queryEntities = new ArrayList();
        //1、所有主键
        List<Serializable> primaryKeyValues = updateBatch(entities);
        if (primaryKeyValues != null && primaryKeyValues.size() > 0) {
            //2、实体Class
            Class<Entity> entityClass = (Class<Entity>) entities.get(0).getClass();
            //3、执行批量查询，（TODO:可优化批量查询，采用 in 方式）
            for (Serializable primaryKeyValue : primaryKeyValues) {
                Entity entity = selectByPrimaryKey(entityClass, primaryKeyValue);
                queryEntities.add(entity);
            }
        }
        return queryEntities;
    }

    @Override
    @SuppressWarnings("unchecked")
    public <Entity extends BaseEntity> List<Entity> updateNotEmptyWithQuery(List<Entity> entities) {
        //
        List<Entity> queryEntities = new ArrayList();
        //1、所有主键
        List<Serializable> primaryKeyValues = updateNotEmptyBatch(entities);
        if (primaryKeyValues != null && !primaryKeyValues.isEmpty()) {
            //2、实体Class
            Class<Entity> entityClass = (Class<Entity>) entities.get(0).getClass();
            //3、执行批量查询，（TODO:可优化批量查询，采用 in 方式）
            for (Serializable primaryKeyValue : primaryKeyValues) {
                Entity entity = selectByPrimaryKey(entityClass, primaryKeyValue);
                queryEntities.add(entity);
            }
        }
        return queryEntities;
    }

    @Override
    @SuppressWarnings("unchecked")
    public <Entity extends BaseEntity> List<Entity> updateNotNullWithQuery(List<Entity> entities) {
        //
        List<Entity> queryEntities = new ArrayList();
        //1、所有主键
        List<Serializable> primaryKeyValues = updateNotNullBatch(entities);
        if (primaryKeyValues != null && !primaryKeyValues.isEmpty()) {
            //2、实体Class
            Class<Entity> entityClass = (Class<Entity>) entities.get(0).getClass();
            //3、执行批量查询，（TODO:可优化批量查询，采用 in 方式）
            for (Serializable primaryKeyValue : primaryKeyValues) {
                Entity entity = selectByPrimaryKey(entityClass, primaryKeyValue);
                queryEntities.add(entity);
            }
        }
        return queryEntities;
    }

    @Override
    public <Entity extends BaseEntity> int save(Entity entity) {
        return this.saveOne(entity).getCount();
    }

    @Override
    public <Entity extends BaseEntity> int save(List<Entity> entities) {
        return this.saveBatch(entities);
    }

    @Override
    public <Entity extends BaseEntity> Entity saveWithQuery(Entity entity) {
        Serializable primaryKeyValue = this.saveOne(entity).getPrimaryKeyValue();
        if (primaryKeyValue == null) {
            return null;
        } else {
            return this.selectByPrimaryKey(entity);
        }
    }

    @Override
    @SuppressWarnings("unchecked")
    public <Entity extends BaseEntity> List<Entity> saveWithQuery(List<Entity> entities) {
        //
        List<Entity> queryEntities = new ArrayList();
        //1、所有主键
        List<Serializable> primaryKeyValues = saveBatchWithPks(entities);
        if (primaryKeyValues != null && primaryKeyValues.size() > 0) {
            //2、实体Class
            Class<Entity> entityClass = (Class<Entity>) entities.get(0).getClass();
            //3、执行批量查询，（TODO:可优化批量查询，采用 in 方式）
            for (Serializable primaryKeyValue : primaryKeyValues) {
                Entity entity = selectByPrimaryKey(entityClass, primaryKeyValue);
                queryEntities.add(entity);
            }
        }
        return queryEntities;
    }

    @Override
    @SuppressWarnings("unchecked")
    public <Entity extends BaseEntity> Entity selectByPrimaryKey(Entity entity) {
        return (Entity) this.selectByPrimaryKey(entity.getClass(), getPrimaryKeyValue(entity));
    }

    @Override
    public <Entity extends BaseEntity> Entity selectByPrimaryKey(Class<Entity> entityClass,
        Serializable primaryKeyValue) {
        BaseMapper entityMapper = MapperUtils.getMapperInstanceByEntityClass(entityClass);
        return entityMapper.selectByPrimaryKey(entityClass, primaryKeyValue);
    }

    @Override
    public <E> List<E> selectListBySql(String statementId) {
        return this.getSqlSession().selectList(statementId);
    }

    @Override
    public <E> List<E> selectListBySql(String statementId, Map<String, Object> parameterMap) {
        return this.getSqlSession().selectList(statementId, parameterMap);
    }

    @Override
    public <K, V> Map<K, V> selectMapBySql(String statementId, Map<String, Object> parameterMap,
        String mapKey) {
        return this.getSqlSession().selectMap(statementId, parameterMap, mapKey);
    }

    @Override
    public <K, V> Map<K, V> selectMapBySql(String statementId, String mapKey) {
        return this.getSqlSession().selectMap(statementId, mapKey);
    }

    @Override
    public <T> T selectOneBySql(String statementId) {
        List<T> list = this.getSqlSession().selectList(statementId);
        if (list == null || list.size() <= 0) {
            return null;
        } else {
            return list.get(0);
        }
    }

    @Override
    public <T> T selectOneBySql(String statementId, Map<String, Object> parameterMap) {
        List<T> list = this.getSqlSession().selectList(statementId, parameterMap);
        if (list == null || list.size() <= 0) {
            return null;
        } else {
            return list.get(0);
        }
    }

    @Override
    public int insertBySql(String statementId, Map<String, Object> parameterMap) {
        return this.getSqlSession().insert(statementId, parameterMap);
    }

    @Override
    public int insertBySql(String statementId, List<Map<String, Object>> parameters) {
        int conut = 0;
        for (Map<String, Object> parameterMap : parameters) {
            conut += this.insertBySql(statementId, parameterMap);
        }
        return conut;
    }

    @Override
    public int deleteBySql(String statementId, Map<String, Object> parameterMap) {
        return this.getSqlSession().delete(statementId, parameterMap);
    }

    @Override
    public int deleteBySql(String statementId, List<Map<String, Object>> parameters) {
        int conut = 0;
        for (Map<String, Object> parameterMap : parameters) {
            conut += this.deleteBySql(statementId, parameterMap);
        }
        return conut;
    }

    @Override
    public int updateBySql(String statementId, Map<String, Object> parameterMap) {
        return this.getSqlSession().update(statementId, parameterMap);
    }

    @Override
    public int updateBySql(String statementId, List<Map<String, Object>> parameters) {
        int conut = 0;
        for (Map<String, Object> parameterMap : parameters) {
            conut += this.updateBySql(statementId, parameterMap);
        }
        return conut;
    }

    @Override
    public int insertByDynamicSql(String sql, Map<String, Object> parameterMap) {
        parameterMap.put(DYNAMIC_SQL, sql);
        return this.insertBySql(DYNAMIC_INSERT_SQL_STATEMENT_ID, parameterMap);
    }

    @Override
    public int insertByDynamicSql(String sql, List<Map<String, Object>> parameters) {
        int conut = 0;
        for (Map<String, Object> parameterMap : parameters) {
            conut += this.insertByDynamicSql(sql, parameterMap);
        }
        return conut;
    }

    @Override
    public int deleteByDynamicSql(String sql, Map<String, Object> parameterMap) {
        parameterMap.put(DYNAMIC_SQL, sql);
        return this.deleteBySql(DYNAMIC_DELETE_SQL_STATEMENT_ID, parameterMap);
    }

    @Override
    public int deleteByDynamicSql(String sql, List<Map<String, Object>> parameters) {
        int conut = 0;
        for (Map<String, Object> parameterMap : parameters) {
            conut += this.deleteByDynamicSql(sql, parameterMap);
        }
        return conut;
    }

    @Override
    public int updateByDynamicSql(String sql, Map<String, Object> parameterMap) {
        parameterMap.put(DYNAMIC_SQL, sql);
        return this.updateBySql(DYNAMIC_UPDATE_SQL_STATEMENT_ID, parameterMap);
    }

    @Override
    public int updateByDynamicSql(String sql, List<Map<String, Object>> parameters) {
        int conut = 0;
        for (Map<String, Object> parameterMap : parameters) {
            conut += this.updateByDynamicSql(sql, parameterMap);
        }
        return conut;
    }

    @Override
    public <K, V> Map<K, V> selectOneByDynamicSql(String sql) {
        return this.selectOneByDynamicSql(sql, new HashMap<String, Object>());
    }

    @Override
    public <K, V> Map<K, V> selectOneByDynamicSql(String sql, Map<String, Object> parameterMap) {
        List<Map<K, V>> maps = this.selectListByDynamicSql(sql, parameterMap);
        if (null != maps && maps.size() > 0) {
            return maps.get(0);
        }
        return null;
    }

    @Override
    public <K, V> List<Map<K, V>> selectListByDynamicSql(String sql) {
        return this.selectListByDynamicSql(sql, new HashMap<String, Object>());
    }

    @Override
    public <K, V> List<Map<K, V>> selectListByDynamicSql(String sql,
        Map<String, Object> parameterMap) {
        parameterMap.put(DYNAMIC_SQL, sql);
        return this.selectListBySql(DYNAMIC_SELECT_SQL_STATEMENT_ID, parameterMap);
    }

    @Override
    public <K, V> Map<K, V> selectMapByDynamicSql(String sql, String mapKey) {
        return this.selectMapByDynamicSql(sql, new HashMap<String, Object>(), mapKey);
    }

    @Override
    public <K, V> Map<K, V> selectMapByDynamicSql(String sql, Map<String, Object> parameterMap,
        String mapKey) {
        parameterMap.put(DYNAMIC_SQL, sql);
        return this.selectMapBySql(DYNAMIC_SELECT_SQL_STATEMENT_ID, parameterMap, mapKey);
    }

    @Override
    public int executeSqls(List<String> sqls, List<Map<String, Object>> parameters) {
        int count = 0;
        if (sqls == null || parameters == null || sqls.size() != parameters.size()) {
            throw new RuntimeException("sqls size mismatch with parameters!");
        } else {
            int size = sqls.size(), i = 0;
            for (; i < size; i++) {
                String sql = sqls.get(i);
                Map<String, Object> parameterMap = parameters.get(i);
                //区分insert,delete,update语句分别执行
                if (insertPattern.matcher(sql.toLowerCase()).matches()) {
                    count += this.insertByDynamicSql(sql, parameterMap);
                }
                if (updatePattern.matcher(sql.toLowerCase()).matches()) {
                    count += this.updateByDynamicSql(sql, parameterMap);
                }
                if (deletePattern.matcher(sql.toLowerCase()).matches()) {
                    count += this.deleteByDynamicSql(sql, parameterMap);
                }
            }
        }
        return count;
    }

    /**
     * 批量新增，返回新增记录总数
     *
     * @param entities 实体集合
     * @return 新增记录总数
     */
    private <Entity extends BaseEntity> int insertListBatch(List<Entity> entities) {
        if (entities == null || entities.isEmpty()) {
            return 0;
        }
        //如果主键没有值，会提供一个32位
        for (Entity entity : entities) {
            setPrimaryKeyValue(entity);
        }
        String statementId = entities.get(0).getClass().getName() + "Mapper.insertList";
        List<Map<String, Object>> parameters = MapUtils.beanListToMapList(entities);
        return this.getSqlSession().insert(statementId, parameters);
    }

    /**
     * 批量新增，返回主键集合
     *
     * @param entities 实体集合
     * @return 主键值集合
     */
    private <Entity extends BaseEntity> List<Serializable> insertBatch(List<Entity> entities) {
        //所有主键
        List<Serializable> primaryKeys = new ArrayList<>();
        //1、批量执行
        for (Entity entity : entities) {
            //2、执行单个新增
            Serializable primaryKeyValue = insertOne(entity);
            if (primaryKeyValue != null) {
                //3、添加主键
                primaryKeys.add(primaryKeyValue);
            }
        }
        return primaryKeys;
    }

    /**
     * 单个新增，返回主键
     *
     * @param entity 实体
     * @return 主键值
     */
    private <Entity extends BaseEntity> Serializable insertOne(Entity entity) {
        //1、主键设值
        setPrimaryKeyValue(entity);
        //2、获取实体mapper实例
        BaseMapper entityMapper = MapperUtils.getMapperInstanceByEntity(entity);
        //3、执行新增
        if (entityMapper.insertSelective(entity) > 0) {
            //4、添加主键
            return getPrimaryKeyValue(entity);
        } else {
            logger.warn(EntityUtil.getTableName(entity.getClass()) + "，新增异常，没有被影响的数据！");
            return null;
        }
    }

    /**
     * 批量更新，返回主键集合
     *
     * @param entities 实体集合
     * @return 主键值集合
     */
    private <Entity extends BaseEntity> List<Serializable> updateBatch(List<Entity> entities) {
        //所有主键
        List<Serializable> primaryKeys = new ArrayList();
        //1、批量执行
        for (Entity entity : entities) {
            //2、执行单个
            Serializable primaryKeyValue = updateOne(entity);
            if (primaryKeyValue != null) {
                //3、添加主键
                primaryKeys.add(primaryKeyValue);
            }
        }
        return primaryKeys;
    }

    /**
     * 批量更新，返回主键集合
     *
     * @param entities 实体集合
     * @return 主键值集合
     */
    private <Entity extends BaseEntity> List<Serializable> updateNotEmptyBatch(
        List<Entity> entities) {
        //所有主键
        List<Serializable> primaryKeys = new ArrayList();
        //1、批量执行
        for (Entity entity : entities) {
            //2、执行单个
            Serializable primaryKeyValue = updateNotEmptyOne(entity);
            if (primaryKeyValue != null) {
                //3、添加主键
                primaryKeys.add(primaryKeyValue);
            }
        }
        return primaryKeys;
    }

    /**
     * 批量更新，返回主键集合
     *
     * @param entities 实体集合
     * @return 主键值集合
     */
    private <Entity extends BaseEntity> List<Serializable> updateNotNullBatch(
        List<Entity> entities) {
        //所有主键
        List<Serializable> primaryKeys = new ArrayList();
        //1、批量执行
        for (Entity entity : entities) {
            //2、执行单个
            Serializable primaryKeyValue = updateNotNullOne(entity);
            if (primaryKeyValue != null) {
                //3、添加主键
                primaryKeys.add(primaryKeyValue);
            }
        }
        return primaryKeys;
    }

    /**
     * 单个更新，返回主键
     *
     * @param entity 实体
     * @return 主键值
     */
    private <Entity extends BaseEntity> Serializable updateOne(Entity entity) {
        //1、获取实体mapper实例
        BaseMapper entityMapper = MapperUtils.getMapperInstanceByEntity(entity);
        //2、执行更新
        if (entityMapper.updateByPrimaryKeySelective(entity) > 0) {
            //3、返回主键
            return getPrimaryKeyValue(entity);
        } else {
            //没有影响到数据，并且实体具有版本字段，抛出乐观锁异常
            if (!StringUtils.isEmpty(EntityUtil.getVersionFileName(entity.getClass()))) {
                throw new OptimisticLockException("乐观锁异常，数据被修改、删除 或 未保存！");
            }
            logger.warn(EntityUtil.getTableName(entity.getClass()) + "，更新异常，没有被影响的数据！");
            return null;
        }
    }

    /**
     * 单个更新(非空字符/非null)，返回主键
     *
     * @param entity 实体
     * @return 主键值
     */
    private <Entity extends BaseEntity> Serializable updateNotEmptyOne(Entity entity) {
        //1、获取实体mapper实例
        BaseMapper entityMapper = MapperUtils.getMapperInstanceByEntity(entity);
        //2、执行更新
        if (entityMapper.updateNotEmptyByPrimaryKey(entity) > 0) {
            //3、返回主键
            return getPrimaryKeyValue(entity);
        } else {
            //没有影响到数据，并且实体具有版本字段，抛出乐观锁异常
            if (!StringUtils.isEmpty(EntityUtil.getVersionFileName(entity.getClass()))) {
                //throw new OptimisticLockException(
                //	"Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect)");
                throw new OptimisticLockException("乐观锁异常，数据被修改、删除 或 未保存！");
            }
            logger.warn(EntityUtil.getTableName(entity.getClass()) + "，更新异常，没有被影响的数据！");
            return null;
        }
    }

    /**
     * 单个更新(非null)，返回主键
     *
     * @param entity 实体
     * @return 主键值
     */
    private <Entity extends BaseEntity> Serializable updateNotNullOne(Entity entity) {
        //1、获取实体mapper实例
        BaseMapper entityMapper = MapperUtils.getMapperInstanceByEntity(entity);
        //2、执行更新
        if (entityMapper.updateNotNullByPrimaryKey(entity) > 0) {
            //3、返回主键
            return getPrimaryKeyValue(entity);
        } else {
            //没有影响到数据，并且实体具有版本字段，抛出乐观锁异常
            if (!StringUtils.isEmpty(EntityUtil.getVersionFileName(entity.getClass()))) {
                //throw new OptimisticLockException(
                //	"Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect)");
                throw new OptimisticLockException("乐观锁异常，数据被修改、删除 或 未保存！");
            }
            logger.warn(EntityUtil.getTableName(entity.getClass()) + "，更新异常，没有被影响的数据！");
            return null;
        }
    }

    /**
     * 单个更新，返回主键 (和saveOne有区别，逻辑改变要同时修改saveOne)
     *
     * @param entity 实体
     * @return 保存结果
     */
    private <Entity extends BaseEntity> SaveResult saveOne(Entity entity) {
        //
        Serializable primaryKeyValue = getPrimaryKeyValue(entity);
        //
        SaveResult saveResult = new SaveResult();
        if (primaryKeyValue == null) {
            //主键为空，未指定状态，默认为新增
            if (insert(entity) > 0) {
                saveResult.setCount(1);
                saveResult.setPrimaryKeyValue(getPrimaryKeyValue(entity));
            }
        } else {
            //主键不为空，未指定状态，默认为修改
            if (update(entity) > 0) {
                saveResult.setCount(1);
                saveResult.setPrimaryKeyValue(primaryKeyValue);
            }
        }
        return saveResult;
    }

    /**
     * 批量更新，返回主键集合
     *
     * @param entities 实体集合
     * @return 主键值集合
     */
    private <Entity extends BaseEntity> List<Serializable> saveBatchWithPks(List<Entity> entities) {
        //所有主键
        List<Serializable> primaryKeys = new ArrayList<>();
        //批量执行
        for (Entity entity : entities) {
            //执行单个
            Serializable primaryKeyValue = saveOne(entity).getPrimaryKeyValue();
            if (primaryKeyValue != null) {
                //添加主键
                primaryKeys.add(primaryKeyValue);
            }
        }
        return primaryKeys;
    }

    /**
     * 批量更新，返回影响行数
     *
     * @param entities 实体集合
     * @return 影像行数
     */
    private <Entity extends BaseEntity> int saveBatch(List<Entity> entities) {
        //所有
        int count = 0;
        //批量执行
        for (Entity entity : entities) {
            //执行单个保存
            count += saveOne(entity).getCount();
        }
        return count;
    }

    /**
     * 设置主键值
     *
     * @param entity 实体
     */
    private <Entity extends BaseEntity> void setPrimaryKeyValue(Entity entity) {
        //主键为空，则设值
        if (null == getPrimaryKeyValue(entity)) {
            entity.setId(UUID.randomUUID().toString());
        }
    }

    /**
     * 获取主键值
     *
     * @param entity 实体
     * @return 主键
     */
    private <Entity extends BaseEntity> Serializable getPrimaryKeyValue(Entity entity) {
        return entity.getId();
    }

    /**
     * 保存单实体结果 1、新增：返回 主键有值，影响1行，成功 2、新增：返回 主键有值，影响0行，失败 3、新增：返回 主键没值，影响0行，失败
     *
     * 1、更新：返回 主键有值，影响1行，成功 2、更新：返回 主键有值，影响0行，失败 3、更新：返回 主键没值，影响0行，失败
     *
     * 1、删除：返回 主键没值，影响1行，成功 2、删除：返回 主键没值，影响0行，失败
     *
     * @author xiezm
     */
    private class SaveResult {

        private Serializable primaryKeyValue = null;

        private int count = 0;

        SaveResult() {
            super();
        }

        Serializable getPrimaryKeyValue() {
            return primaryKeyValue;
        }

        public int getCount() {
            return count;
        }

        void setPrimaryKeyValue(Serializable primaryKeyValue) {
            this.primaryKeyValue = primaryKeyValue;
        }

        public void setCount(int count) {
            this.count = count;
        }

    }
}
